public class CompareArrayCopy
{
	public static void main(String[] args)
	{
		CompareArrayCopy c = new CompareArrayCopy();
		
		//c.noLockWWInt();
		c.systemArrayCopy();
	}

	// ------------------ Positive tests ---------------------

	public void noLockWWInt()
	{
		new ThreadRunner(2)
		{
			public void thread1()
			{
				sharedVar = 1;
			}

			public void thread2()
			{
				sharedVar = 2;
			}
		};
	}

	public void noLockWWShort()
	{
		new ThreadRunner(2)
		{
			short sharedShort;

			public void thread1()
			{
				sharedShort = (short) 1;
			}

			public void thread2()
			{
				sharedShort = (short) 2;
			}
		};
	}

	public void noLockWWChar()
	{
		new ThreadRunner(2)
		{
			char sharedChar;

			public void thread1()
			{
				sharedChar = '1';
			}

			public void thread2()
			{
				sharedChar = '2';
			}
		};
	}

	public void noLockWWLong()
	{
		new ThreadRunner(2)
		{
			long sharedLong;

			public void thread1()
			{
				sharedLong = 1L;
			}

			public void thread2()
			{
				sharedLong = 2L;
			}
		};
	}

	public void noLockWWFloat()
	{
		new ThreadRunner(2)
		{
			float sharedFloat;

			public void thread1()
			{
				sharedFloat = 1.0f;
			}

			public void thread2()
			{
				sharedFloat = 2.0f;
			}
		};
	}

	public void noLockWWDouble()
	{
		new ThreadRunner(2)
		{
			double sharedDouble;

			public void thread1()
			{
				sharedDouble = 1.0;
			}

			public void thread2()
			{
				sharedDouble = 2.0;
			}
		};
	}

	public void noLockWWObject()
	{
		new ThreadRunner(2)
		{
			public void thread1()
			{
				sharedObject = 1L;
			}

			public void thread2()
			{
				sharedObject = 2.0;
			}
		};
	}

	public void lockedVsNoLockedWW()
	{
		new ThreadRunner(2)
		{
			public void thread1()
			{
				sharedVar = 1;
			}

			public void thread2()
			{
				synchronized (this)
				{
					sharedVar = 2;
				}
			}
		};
	}

	public void lockedVsNoLockedWW2()
	{
		new ThreadRunner(2)
		{
			public synchronized void thread1()
			{
				sharedVar++;
			}

			public void thread2()
			{
				sharedVar++;
			}
		};
	}

	public void differentLocksWW()
	{
		new ThreadRunner(2)
		{

			public void thread1()
			{
				synchronized (monitor)
				{
					sharedVar++;
				}
			}

			public void thread2()
			{
				synchronized (this)
				{
					sharedVar++;
				}
			}
		};
	}

	public void recursiveObjectWW()
	{
		new ThreadRunner(2)
		{
			class RecursiveObject
			{
				RecursiveObject next;
				int value;
			}

			RecursiveObject o;

			public void setUp()
			{
				o = new RecursiveObject();
				o.next = new RecursiveObject();
				o.next.next = new RecursiveObject();
				o.next.next.next = o;
			}

			public void thread1()
			{
				o.next.next.next.value = 1;
			}

			public void thread2()
			{
				o.value = 2;
			}
		};
	}

	public void systemArrayCopy()
	{
		new ThreadRunner(2)
		{
			int[] sharedArray;

			public void setUp()
			{
				sharedArray = new int[117];
			}

			public void thread1()
			{
				System.arraycopy(new int[100], 0, sharedArray, 10, 100);
			}

			public void thread2()
			{
				System.arraycopy(sharedArray, 0, new int[30], 0, 20);
			}
		};
	}

	public void systemArrayCopy2()
	{
		new ThreadRunner(2)
		{
			int[] sharedArray;

			public void setUp()
			{
				sharedArray = new int[117];
			}

			public void thread1()
			{
				System.arraycopy(new int[100], 0, sharedArray, 10, 100);
			}

			public void thread2()
			{
				int x = sharedArray[42];
			}
		};
	}

	public void systemArrayCopy3()
	{
		new ThreadRunner(2)
		{
			int[] sharedArray;

			public void setUp()
			{
				sharedArray = new int[117];
			}

			public void thread1()
			{
				sharedArray[42] = 117;
			}

			public void thread2()
			{
				System.arraycopy(sharedArray, 30, new int[30], 0, 20);
			}
		};
	}

	public void systemArrayCopyException()
	{
		new ThreadRunner(2)
		{
			Object[] sharedArray;

			public void setUp()
			{
				sharedArray = new Object[117];
			}

			public void thread1()
			{
				for (int i = 0; i < 10; i++)
				{
					sharedArray[i] = Integer.valueOf(5);
				}
				for (int i = 10; i < 20; i++)
				{
					sharedArray[i] = Double.valueOf(1.1);
				}
			}

			public void thread2()
			{
				shortSleep();
				System.arraycopy(sharedArray, 0, new Integer[30], 0, 20);
			}
		};
	}

	// ------------------ Negative tests ---------------------

	public void noOperation()
	{
		new ThreadRunner(2)
		{
			public void thread1()
			{
				sharedVar = 1;
			}

			public void thread2()
			{
				longSleep();
			}
		};
	}

	public void noOperation2()
	{
		new ThreadRunner(4)
		{
			public void setUp()
			{
				sharedObject = 1L;
			}

			public void thread1()
			{
				// RaceDetectorApi.noOp(sharedObject);
			}

			public void thread2()
			{
				thread1();
			}

			public void thread3()
			{
				thread2();
			}

			public void thread4()
			{
				thread3();
			}
		};
	}

	public void lockedInc()
	{
		new ThreadRunner(2)
		{
			public void thread1()
			{
				synchronized (this)
				{
					sharedVar++;
					longSleep();
				}
			}

			public void thread2()
			{
				thread1();
			}
		};
	}

	public void lockedInc2()
	{
		new ThreadRunner(2)
		{
			public synchronized void thread1()
			{
				sharedVar++;
				longSleep();
			}

			public void thread2()
			{
				thread1();
			}
		};
	}

	public void distinctFields()
	{
		new ThreadRunner(2)
		{
			int field1, field2;

			public void thread1()
			{
				field1 = 1;
			}

			public void thread2()
			{
				field2 = 2;
			}
		};
	}

	public void localVolatileBoolean()
	{
		new ThreadRunner(2)
		{
			volatile boolean volatileBoolean;

			public void thread1()
			{
				volatileBoolean = true;
			}

			public void thread2()
			{
				while (!volatileBoolean)
					;
			}
		};
	}

	public void staticVolatileBoolean()
	{
		new ThreadRunner(2)
		{
			public void thread1()
			{
				staticVolatileBoolean = true;
			}

			public void thread2()
			{
				while (!staticVolatileBoolean)
					;
			}
		};
	}

	public void superClassVolatile()
	{
		new ThreadRunner(2)
		{
			public void thread1()
			{
				sharedVolatile = 1;
			}

			public void thread2()
			{
				sharedVolatile = 2;
			}
		};
	}

	public void syncWithStaticVolatile()
	{
		new ThreadRunner(2)
		{
			public void setUp()
			{
				staticVolatileBoolean = false;
			}

			public void thread1()
			{
				sharedVar = 1;
				staticVolatileBoolean = true;
			}

			public void thread2()
			{
				while (!staticVolatileBoolean)
					;
				sharedVar = 2;
			}
		};
	}

	public void differentFields()
	{
		new ThreadRunner(4)
		{
			Object lock;
			int sharedInt;

			public void setUp()
			{
				sharedInt = 0;
				lock = new Object();
			}

			public void thread1()
			{
				synchronized (lock)
				{
					sharedInt++;
				}
				synchronized (this)
				{
					sharedVar--;
				}
			}

			public void thread2()
			{
				thread1();
			}

			public void thread3()
			{
				thread2();
			}

			public void thread4()
			{}
		};
	}

	public void differentFields2()
	{
		new ThreadRunner(4)
		{
			int a, b;
			Integer c, d;

			public void setUp()
			{
				a = b = c = d = 117;
			}

			public void thread1()
			{
				a++;
			}

			public void thread2()
			{
				b--;
			}

			public void thread3()
			{
				c++;
			}

			public void thread4()
			{
				d--;
			}
		};
	}

	public void lockedWW()
	{
		new ThreadRunner(2)
		{
			public synchronized void thread1()
			{
				sharedVar = 1;
			}

			public void thread2()
			{
				synchronized (this)
				{
					sharedVar = 2;
				}
			}
		};
	}

	public void joinWithoutStart()
	{
		class MyThread extends Thread
		{
			public void run()
			{
				throw new RuntimeException("This code is never running");
			}
		}
		Thread[] t = new Thread[4];
		for (int i = 0; i < 4; i++)
		{
			t[i] = new MyThread();
		}
		try
		{
			for (int i = 0; i < 4; i++)
			{
				t[i].join();
			}
		}
		catch (InterruptedException e)
		{
			throw new RuntimeException("InterruptedException in joinWithoutStart() method ", e);
		}
	}

	public void systemArrayCopyDiff()
	{
		new ThreadRunner(2)
		{
			int[] sharedArray;

			public void setUp()
			{
				sharedArray = new int[117];
			}

			public void thread1()
			{
				System.arraycopy(new int[100], 0, sharedArray, 10, 100);
			}

			public void thread2()
			{
				System.arraycopy(sharedArray, 0, new int[30], 0, 6);
			}
		};
	}

	public void systemArrayCopySync()
	{
		new ThreadRunner(2)
		{
			int[] sharedArray;

			public void setUp()
			{
				sharedArray = new int[117];
			}

			public void thread1()
			{
				synchronized (sharedArray)
				{
					System.arraycopy(new int[100], 0, sharedArray, 10, 100);
				}
			}

			public void thread2()
			{
				synchronized (sharedArray)
				{
					System.arraycopy(sharedArray, 0, new int[30], 0, 20);
				}
			}
		};
	}

	public void systemArrayCopyDiff2()
	{
		new ThreadRunner(2)
		{
			int[] sharedArray;

			public void setUp()
			{
				sharedArray = new int[117];
			}

			public void thread1()
			{
				System.arraycopy(new int[100], 0, sharedArray, 10, 100);
			}

			public void thread2()
			{
				int x = sharedArray[3];
			}
		};
	}

	public void systemArrayCopyDiff3()
	{
		new ThreadRunner(2)
		{
			int[] sharedArray;

			public void setUp()
			{
				sharedArray = new int[117];
			}

			public void thread1()
			{
				sharedArray[27] = 11;
			}

			public void thread2()
			{
				System.arraycopy(sharedArray, 0, new int[30], 0, 20);
			}
		};
	}

	public void systemArrayCopyIndexOutOfBoundsException()
	{
		new ThreadRunner(2)
		{
			int[] sharedArray;

			public void setUp()
			{
				sharedArray = new int[117];
			}

			public void thread1()
			{
				sharedArray[27] = 11;
			}

			public void thread2()
			{
				System.arraycopy(sharedArray, 0, new int[30], 0, 200);
			}
		};
	}

	public void systemArrayCopyNullPointerException()
	{
		new ThreadRunner(2)
		{
			int[] sharedArray;

			public void setUp()
			{
				sharedArray = new int[117];
			}

			public void thread1()
			{
				sharedArray[27] = 11;
			}

			public void thread2()
			{
				System.arraycopy(sharedArray, 0, null, 0, 20);
			}
		};
	}

	public void systemArrayCopyArrayStoreException()
	{
		new ThreadRunner(2)
		{
			int[] sharedArray;

			public void setUp()
			{
				sharedArray = new int[117];
			}

			public void thread1()
			{
				sharedArray[27] = 11;
			}

			public void thread2()
			{
				System.arraycopy(sharedArray, 0, new Object(), 0, 20);
			}
		};
	}
}
